/**
 * @file app.js
 * @description HR SaaS系统服务器应用程序入口文件
 * @author DuYu
 * @date 2025-10-20
 * @version 1.0.0
 * @copyright © 2025 HR SaaS. All rights reserved.
 */

// Node.js 核心模块导入
import http from 'http';
import os from 'os';

// 第三方依赖导入
import Koa from 'koa';
// import cors from '@koa/cors';
import { koaBody } from 'koa-body';

// 业务模块导入
import totalRouter from './src/routes/api/index.js';
import { testConnection } from './src/db/index.js';

/**
 * 创建 Koa3 应用实例
 * @type {Koa}
 * @since 1.0.0
 */
const app = new Koa();

/**
 * 环境配置加载
 * 从环境变量中获取配置，如不存在则使用默认值
 * @since 1.0.0
 */
const NODE_ENV = process.env.NODE_ENV || 'development';
const PORT = parseInt(process.env.PORT, 10) || 3000;
const HOST = process.env.HOST || '127.0.0.1';

process.on('uncaughtException', (err) => {
  console.error('Uncaught Exception:', err);
  // 这里可以添加日志记录或其他处理逻辑
  // 例如，记录到文件或发送到监控系统
  // 确保应用程序能够继续运行
});

process.on('unhandledRejection', (reason, promise) => {
  console.error('Unhandled Rejection at:', promise, 'reason:', reason);
  // 这里可以添加日志记录或其他处理逻辑
  // 确保应用程序能够继续运行
});

/**
 * 根据环境获取允许的跨域来源
 * 开发环境下允许 localhost:8080
 * 生产环境可从环境变量配置或使用更严格的控制
 * @function getAllowedOrigins
 * @returns {Array<string>} 允许的源列表
 * @since 1.0.0
 */
const getAllowedOrigins = () => {
  if (NODE_ENV === 'development') {
    return ['http://localhost:8080'];
  }
  // 生产环境可从环境变量中读取，多个域名用逗号分隔
  return process.env.ALLOWED_ORIGINS
    ? process.env.ALLOWED_ORIGINS.split(',')
    : [];
};

/**
 * CORS 中间件配置
 * 实现跨域资源共享的安全控制
 * @middleware cors
 * @since 1.0.0
 */
// app.use(cors({
//   /**
//    * 动态判断请求来源是否允许
//    * @param {string} origin - 请求来源
//    * @param {Function} callback - 回调函数
//    * @returns {void}
//    */
//   origin: (origin, callback) => {
//     const allowedOrigins = getAllowedOrigins();
//     // 允许来自指定域名的请求或开发环境下的请求
//     const allow = !origin || allowedOrigins.includes(origin);
//     callback(null, allow);
//   },
  
//   /** 允许携带凭证(Cookie) */
//   credentials: true,
  
//   /** 允许的请求头 */
//   allowHeaders: ['Content-Type', 'Authorization', 'X-Requested-With'],
  
//   /** 允许的 HTTP 方法 */
//   allowMethods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS', 'PATCH'],
  
//   /** 预检请求缓存时间(秒) - 设置为 24 小时以减少预检请求数量 */
//   maxAge: 86400,
// }));

/**
 * 请求体解析中间件
 * 处理JSON和表单数据
 * @middleware koaBody
 * @since 1.0.0
 */
app.use(koaBody({
  enableTypes: ['json', 'form'],
  jsonLimit: '1mb',
  formLimit: '56kb',
  strict: true,
  multipart: false,
  onError: (err, ctx) => {
    console.error('Koa Body Error:', err);
    ctx.status = 400;
    ctx.body = { error: 'Bad Request', message: '请求数据格式错误' };
  },
}));

/**
 * 错误处理中间件
 * 捕获并统一处理应用中发生的所有错误
 * @middleware errorHandler
 * @since 1.0.0
 */
app.use(async (ctx, next) => {
  try {
    await next();
    // 处理 404 错误
    if (ctx.status === 404) {
      ctx.status = 404;
      ctx.body = { error: 'Not Found', message: '请求的资源不存在' };
    }
  } catch (error) {
    // 记录错误信息
    console.error('Server Error:', error);
    // 设置错误响应状态码和内容
    ctx.status = error.status || 500;
    ctx.body = {
      error: 'Internal Server Error',
      message: NODE_ENV === 'development' ? error.message : '服务器内部错误',
      ...(NODE_ENV === 'development' && { stack: error.stack })
    };
    // 触发 Koa 的错误事件
    ctx.app.emit('error', error, ctx);
  }
});

/**
 * 统一响应工具中间件
 * 为上下文添加统一的响应方法
 * @middleware responseFormatter
 * @since 1.0.0
 */
app.use(async (ctx, next) => {
  /**
   * 统一响应工具方法
   * @param {Error|string} err - 错误信息/Error对象
   * @param {Boolean} [success=false] - 业务状态码（true=成功，false=失败）
   * @param {object} [data=null] - 成功时返回的业务数据
   */
  ctx.cc = function(err, success = false, data = null, code=20001) {
    ctx.body = {
      code,
      data, // 仅当data存在时才返回该字段
      message: err instanceof Error ? err.message : err,
      success
    };
  };
  
  await next(); // 传递中间件链，避免阻塞请求
});

// 应用路由中间件
app.use(totalRouter.routes()).use(totalRouter.allowedMethods());

/**
 * 全局错误事件监听
 * 可用于日志记录、告警等
 * @event error
 * @param {Error} err - 错误对象
 * @param {Context} ctx - Koa上下文
 * @since 1.0.0
 */
app.on('error', (err, ctx) => {
  console.error('App Error:', err);
  // 在生产环境中，可以集成错误监控系统如 Sentry
  // sentry.captureException(err, { extra: { request: ctx.request } });
});

/**
 * 创建 HTTP 服务器实例
 * 分离应用和服务器，便于测试和扩展
 * @type {http.Server}
 * @since 1.0.0
 */
const server = http.createServer(app.callback());

/**
 * 启动服务器
 * @function startServer
 * @returns {void}
 * @since 1.0.0
 */
const startServer = () => {
  const startTime = new Date().toISOString();
  server.listen(PORT, HOST, () => {
    console.log(`[${startTime}] HR SaaS Server - Environment: ${NODE_ENV}`);
    console.log(`[${startTime}] Server listening on ${HOST}:${PORT} (PID: ${process.pid})`);
    console.log(`[${startTime}] Access URL: http://localhost:${PORT}`);
    
    // 测试数据库连接
    testConnection();
    
    // 在开发环境中显示额外信息
    if (NODE_ENV === 'development') {
      displayNetworkAddresses(startTime);
    }
  });
};

/**
 * 显示所有网络接口的访问地址
 * 仅在开发环境中显示
 * @function displayNetworkAddresses
 * @param {string} timestamp - 时间戳
 * @returns {void}
 * @since 1.0.0
 */
const displayNetworkAddresses = (timestamp) => {
  const networkInterfaces = os.networkInterfaces();
  const addresses = [];
  
  // 获取所有网络接口的 IP 地址
  Object.keys(networkInterfaces).forEach((iface) => {
    networkInterfaces[iface].forEach((alias) => {
      if (alias.family === 'IPv4' && !alias.internal) {
        addresses.push(`http://${alias.address}:${PORT}`);
      }
    });
  });
  
  if (addresses.length > 0) {
    console.log(`[${timestamp}] Network Access URLs:`);
    addresses.forEach((url) => console.log(`[${timestamp}] - ${url}`));
  }
};

/**
 * 优雅关闭处理
 * 处理进程终止信号，确保服务器安全退出
 * @function shutdown
 * @returns {void}
 * @since 1.0.0
 */
const shutdown = () => {
  const endTime = new Date().toISOString();
  console.log(`[${endTime}] Server is shutting down gracefully...`);
  
  // 关闭服务器，允许现有连接完成
  server.close((err) => {
    if (err) {
      console.error('Error during server shutdown:', err);
      process.exit(1);
    }
    console.log(`[${endTime}] Server has been shut down successfully`);
    process.exit(0);
  });
  
  // 设置超时强制退出
  setTimeout(() => {
    console.error('Forcing server shutdown due to timeout');
    process.exit(1);
  }, 10000);
};

// 启动服务器
startServer();

// 监听终止信号
process.on('SIGTERM', shutdown);
process.on('SIGINT', shutdown);

/**
 * 导出 app 和 server 实例
 * 便于测试和其他模块引用
 * @exports
 * @since 1.0.0
 */
export { app, server };
